import threading

class _ContextManager:
    """
    上下文管理器类

    作者：魏文海
    参考：基于单例模式和线程局部存储实现的上下文管理器

    这是一个用于管理每个线程上下文数据的类，确保在多线程环境中数据的隔离性。通过使用线程局部存储 (`threading.local()`) 来存储上下文数据，确保每个线程的数据互不干扰。该类支持设置、获取、追加和清空上下文数据。

    相较于普通的上下文管理方式，本类具有以下优势：
    - 使用线程局部存储来保证数据在多线程环境中的隔离性。
    - 提供了设置、获取、追加和清空上下文数据的方法。
    - 支持将单个值或多个值存储在上下文中，方便数据的管理和使用。
    - 增强了上下文数据的可读性和管理性。

    方法：
        - set_value(key, value): 设置指定键的上下文数据值。
        - get_value(key): 获取指定键的上下文数据值。如果键不存在则返回 None。
        - append_value(key, value): 在指定键的上下文数据值中追加新值。如果值已是列表则追加到列表中，否则将当前值和新值放入列表中。
        - clear(): 清空当前线程的上下文数据。
        - __str__(): 返回当前线程的上下文数据的字符串表示，便于调试和输出。
    """
    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        """
        实现单例模式，确保系统中只能有一个 ContextManager 实例。
        使用双重检查锁机制确保线程安全。
        """
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._instance._initialize()
        return cls._instance

    def _initialize(self):
        """
        初始化 ContextManager 实例，使用线程局部存储来确保每个线程的上下文数据是独立的。
        """
        self._thread_local = threading.local()

    def _ensure_data_initialized(self):
        """
        确保线程局部存储中的 data 字典已经初始化。如果未初始化，则进行初始化。
        """
        if not hasattr(self._thread_local, 'data'):
            self._thread_local.data = {}

    def set_value(self, key, value):
        """
        设置指定键的上下文数据值。

        :param key: 键，用于标识上下文数据项。
        :param value: 要设置的数据值。
        """
        self._ensure_data_initialized()
        self._thread_local.data[key] = value

    def get_value(self, key):
        """
        获取指定键的上下文数据值。如果键不存在，则返回 None。

        :param key: 键，用于获取上下文数据项。
        :return: 对应键的数据值，如果键不存在则返回 None。
        """
        self._ensure_data_initialized()
        return self._thread_local.data.get(key, None)

    def append_value(self, key, value):
        """
        在指定键的上下文数据值中追加新值。如果键当前的值是列表，则将新值追加到列表中；否则，将当前值和新值放入一个新的列表中。

        :param key: 键，用于标识要追加数据的上下文数据项。
        :param value: 要追加的数据值。
        """
        self._ensure_data_initialized()
        if key in self._thread_local.data:
            if isinstance(self._thread_local.data[key], list):
                self._thread_local.data[key].append(value)
            else:
                self._thread_local.data[key] = [self._thread_local.data[key], value]
        else:
            self._thread_local.data[key] = [value]

    def clear(self):
        """
        清空当前线程的上下文数据。调用此方法后，当前线程的所有上下文数据将被删除。
        """
        self._ensure_data_initialized()
        self._thread_local.data.clear()

    def format_data(self):
        """
        格式化上下文数据，用于日志记录。以键值对的形式输出，便于日志分析。
        """
        self._ensure_data_initialized()
        
        formatted_data = {
            "request_time": self._thread_local.data.get("request_time"),  # 记录当前请求的时间信息
            "request_url": self._thread_local.data.get("request_url"),  # 记录当前请求的URL
            "service_name": self._thread_local.data.get("service_name"),  # 记录当前请求的服务名称
            "user_id": self._thread_local.data.get("user_id"),  # 记录当前请求的用户ID
            "username": self._thread_local.data.get("username"),  # 记录当前请求的用户信息
            "inter_service_name":self._thread_local.data.get("inter_service_name"),  # 记录生命周期中间过程中调用的服务名称
            "process_info": self._thread_local.data.get("process_info"),  # 记录生命周期过程中产生的信息
            "error_message": self._thread_local.data.get("error_message"),  # 记录错误信息
            "exec_time": self._thread_local.data.get("exec_time")  # 记录执行时间
        }
        
        # 过滤掉 None 的值，使得日志更加简洁
        return {k: v for k, v in formatted_data.items() if v is not None}


    def __str__(self):
        """
        返回当前线程的上下文数据的字符串表示形式，用于调试和输出。

        :return: 当前线程上下文数据的字符串表示。
        """
        self._ensure_data_initialized()
        return str(self._thread_local.data)
    
    def destroy(self):
        """
        销毁 ContextManager 实例，释放资源。
        """
        with self._lock:
            if self._instance is None:
                return
            self.clear()
            self._instance = None